#include "Binding/BoundNode.hpp"
#include "Binding/BoundBinary.hpp"
#include "Binding/BoundUnary.hpp"

std::map<BoundNodeKind, std::string> BoundNode::KindAllName = {
    // expression;
    {BoundNodeKind::LiteralExpression, "LiteralExpression"},
    {BoundNodeKind::UnaryExpression, "UnaryExpression"},
    {BoundNodeKind::BinaryExpression, "BinaryExpression"},
    {BoundNodeKind::VariableExpression, "VariableExpression"},
    {BoundNodeKind::AssignmentExpression, "AssignmentExpression"},

    // statements;
    {BoundNodeKind::IfStatement, "IfStatement"},
    {BoundNodeKind::ForStatement, "ForStatement"},
    {BoundNodeKind::GotoStatement, "GotoStatement"},
    {BoundNodeKind::LabelStatement, "LabelStatement"},
    {BoundNodeKind::WhileStatement, "WhileStatement"},
    {BoundNodeKind::BlockStatement, "BlockStatement"},
    {BoundNodeKind::ExpressionStatement, "ExpressionStatement"},
    {BoundNodeKind::VariableDeclaration, "VariableDeclaration"},
    {BoundNodeKind::ConditionalGotoStatement, "ConditionalGotoStatement"},
};

void BoundNode::PrettyPrint(std::ostream &os, BoundNode *node, std::string indent, bool isLast)
{
    std::string marker = isLast ? "└──" : "├──";

    os << indent << marker << GetText(node);

    // auto Properties = node->GetProperties();

    bool isFirstProperty = true;
    for (auto [name, value] : node->GetProperties())
    {
        if (isFirstProperty)
            isFirstProperty = false;
        else
            os << ",";
        os << " " << name << "=" << value;
    }

    os << std::endl;

    indent += isLast ? "   " : "│  ";

    const size_t childrenSize = node->GetChildren().size();

    for (int i = 0; i < childrenSize; i++)
    {
        PrettyPrint(os, node->GetChildren()[i].get(), indent, i == (childrenSize - 1));
    }
}
std::string BoundNode::GetText(BoundNode *node)
{
    if (node->GetKind() == BoundNodeKind::BinaryExpression)
    {
        auto bin = (BoundBinaryExpression *)node;
        return bin->Op->GetTypeName() + "Expression";
    }

    if (node->GetKind() == BoundNodeKind::UnaryExpression)
    {
        auto u = (BoundUnaryExpression *)node;
        return u->Op->GetTypeName() + "Expression";
    }
    return BoundNode::KindAllName[node->GetKind()];
}